import platform = require('../common/basecommon');
import appServer = require('./appServer');
import orm = require('typeorm');
import "reflect-metadata";
// import moduleName=require('../common/moduleName');

/**
 * 模块名称
 */
const moduleName = "platform.server";

/**
 * 默认数据库名称
 */
const defaultDatabaseName = "default";


/**
 * 数据过滤器接口
 */
export interface filterObject {
    /**
     * 获取运算符
     */
    getLogicSign?(): string;
    /**
     * 获取过滤语句
     * @param paramValues 参数
     */
    getFilterSql?(paramValues: {} | any): string;
    /**
     * 获取参数
     */
    getParameters?(paramValues: {} | any): Array<any>;
}

/**
 * 数据过滤器
 */
@platform.addon("数据过滤器", "数据过滤器", moduleName)
export class baseDataFilter extends platform.baseObject implements filterObject {
    /**
     * 子过滤器列表
     */
    childFilters: filterObject[];
    parameters?: any[] = undefined;
    /**
     * 获取过滤语句
     * @param paramValues 参数
     */
    getFilterSql?(paramValues: {} | any): string {
        let where: string = undefined;
        // 当前过滤器对象
        let that = this;
        if (that.childFilters) {
            let composite = false;
            // 遍历子过滤器列表,根据传入参数返回过滤语句,并拼接
            // 拼接完后,如果是组合型的过滤语句则加()返回
            for (let filter of that.childFilters) {
                let filterSql = filter.getFilterSql(paramValues);
                let param = filter.getParameters(paramValues);
                if (filterSql) {
                    if (where) {
                        where += ` ${that.getLogicSign()} ${filterSql}`;
                        composite = true;
                    } else {
                        where = filterSql;
                        this.parameters = [];
                    }
                    this.parameters = this.parameters.concat(param);
                }
            }
            if (composite) {
                where = ` (${where}) `;
            }
        }
        return where;
    }
    getParameters?(paramValues: {} | any): Array<any> {
        return this.parameters;
    }
    getLogicSign?(): string;
    /**
     * AND逻辑运算
     * @param filters 表达式
     * @remark 传入的表示式可以是sqlFilter或者baseDataFilter,
     * 如果是baseDataFilter,则baseDataFilter生成表达式会用()闭包
     * 例如(sqlfilter,baseDataFilter)生成结果(sqlFilterSql and ( baseDataFilterSql ) )
     */
    and?(...filters: filterObject[]): baseDataFilter {
        if (!this.childFilters) {
            this.childFilters = [];
        }
        let andFilters = new andLogicFilter();
        andFilters.childFilters = [];
        for (let f of filters) {
            andFilters.childFilters.push(f);
        }
        this.childFilters.push(andFilters);
        return this;
    }

    /**
     * OR逻辑运算
     * @param filters 表达式
     * @remark 和and方法一样,只是最后是使用OR的逻辑运算符
     */
    or?(...filters: filterObject[]): baseDataFilter {
        if (!this.childFilters) {
            this.childFilters = [];
        }
        let orFilters = new orLogicFilter();
        orFilters.childFilters = [];
        for (let f of filters) {
            orFilters.childFilters.push(f);
        }
        this.childFilters.push(orFilters);
        return this;
    }

    /**
     * 添加筛选类型的过滤条件
     * @param filters 筛选类型的过滤条件
     * @remark 筛选类型:group by/having/limit等
     */
    add?(...filters: filterObject[]): baseDataFilter {
        if (!this.childFilters) {
            this.childFilters = [];
        }
        for (let f of filters) {
            this.childFilters.push(f);
        }
        return this;
    }
}

/**
 * AND逻辑运算过滤器
 */
@platform.addon("AND逻辑运算过滤器", "AND逻辑运算过滤器", moduleName)
export class andLogicFilter extends baseDataFilter implements filterObject {
    getLogicSign?(): string {
        return "AND";
    }
}

/**
 * OR逻辑运算过滤器
 */
@platform.addon("OR逻辑运算过滤器", "OR逻辑运算过滤器", moduleName)
export class orLogicFilter extends baseDataFilter implements filterObject {
    getLogicSign?(): string {
        return "OR";
    }
}

/**
 * SQL语句过滤器
 */
@platform.addon("SQL语句过滤器", "SQL语句过滤器", moduleName)
export class sqlFilter extends platform.dataField implements filterObject {
    /**
     * SQL过滤语句
     * @remark 如"name=?或者name=:name"
     */
    sql?: string;

    constructor(name: string, sql: string, caption?: string) {
        super();
        this.name = name;
        this.sql = sql;
        this.caption = caption;
    }

    /**
     * 获取过滤语句
     * @param paramValues 参数
     */
    getFilterSql?(paramValues: {} | any): string {
        try {
            if (paramValues && paramValues[this.name]) {
                return this.sql;
            }
        } catch (e) {
            return undefined;
        }
    }
    /**
     * 获取参数
     * @param paramValues 参数列表
     */
    getParameters?(paramValues: {} | any): Array<any> {
        try {
            if (paramValues && paramValues[this.name]) {
                let params: Array<any> = [];
                params.push(paramValues[this.name]);
                return params;
            }
        } catch (e) {
            return undefined;
        }
    }
}


/**
 * 数据命令
 */
@platform.addon("数据命令对象", "用于保存数据命令的对象", moduleName)
export class dataCommandInfo extends platform.baseObject {
    /**
     * 命令ID
     */
    id: string;
    /**
     * 名称
     */
    name: string;

    /**
     * SQL语句
     */
    sql: string;

    /**
     * 表名
     */
    tableName?: string;

    /**
     * 主键
     */
    primaryKey?: string[];

    /**
     * 是否为多表查询(默认为多表查询)
     */
    isMultitableQuery: boolean = true;

    /**
     * TRUE条件过滤字符串
     */
    private trueFilterString?: string = "1=1";

    /**
     * 参数
     */
    private parameters: any[] = undefined;

    /**
     * 数据过滤器
     */
    dataFilter?: baseDataFilter[];

    /**
     * 获取命令字符串
     * @param paramValues 查询参数
     */
    getCommandText?(paramValues: {}): string {
        if (!this.dataFilter) {
            return this.sql;
        }

        let filterStrings: string[] = [];
        this.parameters = [];
        for (let filter of this.dataFilter) {
            let filterString = filter.getFilterSql(paramValues);
            let param = filter.getParameters(paramValues);
            if (!filterString || filterString == "") {
                filterString = this.trueFilterString;
            }
            if (param) {
                this.parameters = this.parameters.concat(param);
            }
            filterStrings.push(filterString);
        }

        return platform.format(this.sql, filterStrings);
    }
    /**
     * 获取过滤参数
     */
    getParameters?(): any[] {
        return this.parameters;
    }

    /**
     * 清空过滤参数
     */
    clearParameters?() {
        this.parameters = undefined;
    }

    /**
     * 清空过滤参数
     */
    clearDataFilter() {
        if (this.dataFilter == undefined || this.dataFilter.length == undefined) {
            return;
        }
        for (let item of this.dataFilter) {
            item.parameters = undefined;
        }
    }
}

/**
 * 数据连接对象
 */
@platform.addon("数据连接对象", "用于保存数据连接的对象", moduleName)
export class dataConnectionInfo extends platform.baseObject {

    /**
     * 数据库连接配置
     * @remark 可以是连接的字符串，或者连接的配置对象
     */
    dbConnection?: orm.ConnectionOptions;

    /**
     * 当前TypeORM的连接对象
     */
    private _currentConnection?: orm.Connection = undefined;

    private databaseManager: orm.ConnectionManager;

    /**
     * 连接数据库
     */
    async connect?(): Promise<orm.Connection> {
        if (!this.databaseManager) {
            this.databaseManager = orm.getConnectionManager();
        }
        if (this.dbConnection) {
            // 当前数据库连接的名称
            let databaseName = this.dbConnection.name ? this.dbConnection.name : defaultDatabaseName;
            if (this.databaseManager.has(databaseName)) {
                this._currentConnection = this.databaseManager.get(databaseName);
            } else {
                this._currentConnection = this.databaseManager.create(this.dbConnection);
            }
        }
        // 关闭
        if (this._currentConnection.isConnected) {
            await this._currentConnection.close();
        }
        // 返回连接的Promise对象
        return await this._currentConnection.connect();
    }
}

/********    数据服务      ********/
/**
 * 数据查询器:数据库
 */
@platform.addon("数据服务", "通过数据库获取数据的服务", moduleName)
export class dataService extends platform.baseService implements platform.IDataService {
    /**
     * 数据连接信息
     */
    connectionInfo: dataConnectionInfo | any;

    /**
     * 命令列表
     */
    commandList: dataCommandInfo[];

    /**
     * 获取命令信息
     * @param commandID 命令ID
     */
    getCommandByID?(commandID: string): dataCommandInfo {
        if (this.commandList) {
            for (let cmd of this.commandList) {
                if (cmd.id == commandID) {
                    return cmd;
                }
            }
        }
        return undefined;
    }

    /**
     * 源数据转Table对象
     * @param origin 
     */
    toTable(origin: any): platform.dataTable {
        let table: platform.dataTable = new platform.dataTable();
        table.rows = [];
        // 列
        if (origin.length > 0) {
            for (let key in origin[0]) {
                let column = new platform.dataColumn();
                column.name = key;
                column.caption = key;
                table.addColumn(column);
            }
        }
        // 行
        for (let index in origin) {
            table.rows[index] = new platform.dataRow();
            table.rows[index].rowValues = {};
            for (let key in origin[index]) {
                (table.rows[index].rowValues)[key] = origin[index][key];
            }
        }
        return table;
    }

    /**
     * 查询
     * @param command 查询命令，可以是命令ID也可以是命令字符串
     * @param startIndex 起始索引
     * @param maxCount 最大行数
     * @param paramValues 参数值
     */
    query(command: string, paramValues: {}, startIndex: number = 0, maxCount: number = 500): Promise<platform.dataTable> {
        // 数据库连接对象
        let connectionInfo: dataConnectionInfo = undefined;
        try {
            // 获取命令,ID则获取
            let cmd = this.getCommandByID(command);
            if (!cmd) {
                throw new Error(`找不到[${command}]的命令`);
            }
            // 待执行的SQL语句
            let executeSql = cmd.getCommandText(paramValues);
            let param = cmd.getParameters();
            connectionInfo = platform.getObject<dataConnectionInfo>(this.connectionInfo);
            // 数据库不存在,或者数据库连接错误
            if (!connectionInfo) {
                throw new Error(`数据库不存在,或者数据库连接错误`);
            }
            return connectionInfo.connect()
                .then(connection => {
                    return connection.query(executeSql, param);
                })
                .then(result => {
                    // 获取分页
                    let page = result.slice(0).splice(startIndex, maxCount);
                    return this.toTable(page);
                })
                .catch(error => {
                    throw new Error(`执行语句[${executeSql}]，发生异常:${error.message}`);
                });
        } catch (error) {
            throw error;
        }
    }

    /**
     *  查询数据最大条数
     * @param command 
     * @param paramValues 
     */
    queryCount(command: string, paramValues: {}): Promise<number> {
        return undefined;
    }

    /**
     * 更新表格
     * @param datatable 
     */
    updateTable(datatable: platform.dataTable): Promise<number> {
        return undefined;
    }

    /**
     * 查询表格信息
     * @param tableName  表名
     */
    queryTableInfo(tableName: string): Promise<platform.DataTableInfo> {
        return undefined;
    }
    /** 获取表结构 */
    getTableSchema(command: string): Promise<platform.dataTable> {
        let filterSqlFormat = `select temp.* from ({0}) temp where 1=0`;
        let connectionInfo = platform.getObject<dataConnectionInfo>(this.connectionInfo);
        // 获取命令,ID则获取
        let cmd = this.getCommandByID(command);
        if (!cmd) {
            throw new Error(`找不到[${command}]的命令`);
        }
        // 待执行的SQL语句
        let executeSql = cmd.getCommandText({});
        let filterSql = platform.format(filterSqlFormat, executeSql);
        return connectionInfo.connect()
            .then(connection => {
                return connection.query(filterSql);
            })
            .then(result => {
                // 获取分页
                return this.toTable(result);
            })
            .catch(error => {
                throw new Error(`执行语句[${executeSql}]，发生异常:${error.message}`);
            });
    }
}

